import axios, { AxiosPromise } from 'axios'
import store from '@/store'
import { Message } from 'element-ui'
import qs from 'qs'
import router from '@/router'
const request = axios.create()

// 添加请求拦截器
request.interceptors.request.use(function(config) {
  // 在发送请求之前做些什么
  const { user } = store.state
  if (user && user.access_token) {
    const headers = {
      ...config.headers,
      Authorization: user.access_token
    }
    config.headers = headers
  }
  return config
}, function(error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

/*
/ 1.验证token过期为啥不放在请求拦截器里，因为不安全，前端的过期时间跟本地时间对比，如果更改了本地时间，很有可能跳过拦截
* 2.处理token过期，放在响应拦截器里，如果一个接口响应失败，且返回没有像权限，则可以通过refresh_token去刷新access_token，如果刷新失败或者没有refresh_token，则直接跳登录页面
*/

let isRefreshToken = false
let failRequestList: any[] = []
// 添加响应拦截器
request.interceptors.response.use(function(response) {
  // 2xx 范围内的状态码都会触发该函数。
  // 对响应数据做点什么
  return response
}, function(error) {
  // 超出 2xx 范围的状态码都会触发该函数。
  if (error.response) {
    switch (error.response.status) {
      case 401: {
        try {
          const { user } = store.state
          if (user && user.refresh_token) {
            if (!isRefreshToken) {
              isRefreshToken = true
              refreshToken(user.refresh_token)
                .then(({ data }) => {
                  store.commit('setUser', data.content)
                  // 重新发送失败的请求
                  failRequestList.forEach(callback => callback())
                  failRequestList = []
                }).catch((error) => {
                  redirectLogin()
                  return Promise.reject(error)
                }).finally(() => {
                  isRefreshToken = false
                })
            }
          }
          // 当请求失败时，先把失败的请求存储起来，等待刷新token之后再去重新请求
          return new Promise((resolve) => {
            failRequestList.push(() => {
              resolve(request(error.config))
            })
          })
        } catch (error) {
          return Promise.reject(error)
        }
        break
      }
      case 403:
        Message.error('没有权限，请联系管理员！')
        break
      case 404:
        Message.error('请求资源不存在！')
        break
      default:
        Message.error('服务器错误，请联系管理员！')
        break
    }
  } else if (error.request) {
    Message.error('请求超时，请稍后再试！')
  }
  return Promise.reject(error)
})

function refreshToken(token: string): AxiosPromise<any> {
  return axios.post('/front/user/refresh_token', qs.stringify({
    refreshtoken: token
  }))
}

function redirectLogin() {
  const redirect = router.currentRoute.fullPath
  router.push({
    name: 'login',
    query: {
      redirect
    }
  })
}

export default request
